package com.zz.springboot.shiro;

import com.zz.springboot.dto.UserDto;
import com.zz.springboot.exception.BizException;
import com.zz.springboot.manager.UserManager;
import com.zz.springboot.resp.enums.RespCodeEnum;
import com.zz.springboot.service.UserService;
import com.zz.springboot.util.DateUtils;
import com.zz.springboot.util.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import java.util.Date;
import java.util.List;

/**
 * 自定义 Realm
 */
@Slf4j
public class UserRealm extends AuthorizingRealm {


    /**
     * 授权
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // 获取用户名（主身份）
        String username = (String) principals.getPrimaryPrincipal();

        // 查询用户的角色和权限（示例：调用 service 层）
        UserManager userManager = SpringUtil.getBean(UserManager.class);
        UserDto user = userManager.selectUserByUsername(username);
        if (user == null) {
            log.error("用户[{}]不存在", username);
            throw new BizException(RespCodeEnum.USER_NOT_EXISTS);
        }
        // 查询用户的角色
        List<String> roles = userManager.getRolesByUserName(username);
        log.info("用户[{}]的角色为[{}]", username, roles);
        // 查询用户的权限
        List<String> perms = userManager.getPermissionsByUserName(username);
        log.info("用户[{}]的权限为[{}]", username, perms);

        // 创建授权信息对象
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.addRoles(roles);
        authorizationInfo.addStringPermissions(perms);

        return authorizationInfo;
    }

    /**
     * 认证
     *
     * @tips 在认证方法中，无需使用原生密码校验，因为shiro已经做了密码校验
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        String username = upToken.getUsername();
        // 用户认证（UserRealm不是一个spring bean，所以不能通过直接@Autowired注入对象）
        UserService userService = SpringUtil.getBean(UserService.class);
        UserDto user = userService.selectUserByUsername(username);
        if (user == null) {
            log.error("用户[{}]不存在或不可用", username);
            throw new UnknownAccountException("用户名或密码错误");
        }
        //验证有效期
        Integer setValidDays = userService.selectUserValidDaysByUsername(username);
        Date currentTime = DateUtils.getCurrentTime("yyyy-MM-dd");
        Date createTime = DateUtils.truncateToYMD(user.getCreatedAt());
        long daysDiff = (currentTime.getTime() - createTime.getTime()) / (24 * 60 * 60 * 1000);
        if (daysDiff > setValidDays) {
            log.error("用户[{}]已过期", username);
            throw new AuthenticationException("用户账号已过期");
        }
        log.info("用户{}有效天数剩余{}天", username, setValidDays - daysDiff);

        return new SimpleAuthenticationInfo(
                username,
                user.getPassword(), //数据库中的加密密码
                ByteSource.Util.bytes(username), //盐
                getName()
        );
    }
}
